<?php
/**
 * FastApp.
 * 8/12/24
 * @Author 深色的海 (wx:deepsea_0024)
 * @Contact telegram:deepsea159
 */

namespace App\Fastapp\Api\Service\Pay\Platform;

use App\Fastapp\Api\Service\Account\WalletService;
use App\Fastapp\Listener\Event\AccountOrderPayEvent;
use App\Fastapp\Model\AccountRecharge;
use App\Fastapp\Model\AccountWithdrawal;
use App\Fastapp\Model\FastappPay;
use App\Mall\Model\MallOrder;

class XwinpayService
{
    const KEY = 'xwinpay';
    public static array $config = [];

    public static function pay(array $data): array
    {
        $cpf = $data['cpf'];
        $param = [
            'amount' => (float)$data['amount'],
            'merchantOrderNo' => $data['order_id'],
        ];
        if ($cpf && strlen('' . $cpf) == 11) $param['cpf'] = $cpf;

        $res = self::post('/bra/openapi/payIn', $param);
        if (empty($res['data'])) return $res;
        return [
            'url' => $res['data']['payUrl'],
            'qrCode' => $res['data']['qrCode'],
            'trans_no' => $res['data']['plaOrderNo'],
            'out_trade_no' => $data['order_id'],
            'amount' => floatval($data['amount']),
            'to_no' => self::getConfig()['merchant_id']
        ];
    }

    public static function payOut(AccountWithdrawal $md): bool
    {
        try {
            $data = self::post('/bra/openapi/payOut', [
                'amount' => floatval($md->amount),
                'merchantOrderNo' => 'W' . $md->id,
                'accountType' => 'CPF',
                'accountNumber' => $md->account,
                'accountName' => 'withdrawal' . $md->user_id,
            ]);
            if ($data['success']) {
                return true;
            }
        } catch (\Throwable $throwable) {
            sys_notify('代付失败: 提现id ' . $md->id . ' ' . $throwable->getMessage());
        }
        return false;
    }

    public static function payed(array $data): string
    {
//        $sign = $data['sign'];
//        unset($data['sign']);
//        $s = XwinpayRSAUtils::encryptByPrivateKey(self::sign($data), self::getConfig()['private_key']);
//        if ($sign != $s) return 'fail';
        if (!redis()->setnx($data['merchantOrderNo'], 1)) return 'fail';
        redis()->expire($data['merchantOrderNo'], 60);
        $map['id'] = substr($data['merchantOrderNo'], 1);
        if ($data['status'] == 'COMPLETED') {
            try {
                $type = substr($data['merchantOrderNo'], 0, 1);
                $map['status'] = 0;
                if ($type == 'R') {//充值
                    $md = AccountRecharge::query()->where($map)->first();
                    if ($md) {
                        $md->trade_no = $data['plaOrderNo'];
                        WalletService::recharge($md);
                    }
                } elseif ($type == 'O') {//下单支付
                    $md = MallOrder::query()->where(['id' => $map['id'], 'is_pay' => 0])->first();
                    if ($md) {
                        MallOrder::query()->where(['id' => $map['id'], 'is_pay' => 0])->update(['is_pay' => 1, 'pay_at' => date('Y-m-d H:i:s')]);
                        api_dispatch(new AccountOrderPayEvent($md->user_id, $md->id, get_user_cache('type', $md->user_id)));
                    }
                } elseif ($type == 'W') {//提现
                    $map['status'] = 1;
                    $md = AccountWithdrawal::query()->where($map)->first();
                    if (!empty($data['fee'])) $md->pump = bcadd($md->pump, $data['fee']);
                    $md?->update(['pay_status' => 1]);
                }
            } catch (\Throwable $throwable) {
                console()->error($throwable->getMessage());
                redis()->del($data['merchantOrderNo']);
                return 'fail';
            }
        }
        return 'success';
    }

    public static function post($uri, $param)
    {
        $config = self::getConfig();
        $param['channelCode'] = 'PIX';
        $param['currency'] = 'BRL';
        $param['timestamp'] = time() * 1000;
        $param['notifyUrl'] = $config['notifyUrl'];
        $param['redirectUrl'] = $config['redirectUrl'];
        $data['param'] = $param;
        $data['sign'] = XwinpayRSAUtils::encryptByPrivateKey(self::sign($param), self::getConfig()['private_key']);

        $curl = curl_init();
        curl_setopt_array($curl, [
            CURLOPT_URL => $config['url'] . $uri,
            CURLOPT_RETURNTRANSFER => true,
            CURLOPT_POST => true,
            CURLOPT_POSTFIELDS => json_encode($data),
            CURLOPT_HTTPHEADER => [
                'Content-Type: application/json',
                'X-MERCHANT-CODE: ' . self::getConfig()['merchant_id'],
                'X-API-KEY: ' . self::getConfig()['api_key']
            ],
        ]);
        $response = curl_exec($curl);
        curl_close($curl);
        return json_decode($response, true);
    }

    public static function sign(array $param): string
    {
        $keys = array_keys($param);
        sort($keys);
        $sign = '';
        foreach ($keys as $k) {
            $val = $param[$k];
            if ($val !== '' && $val !== null && $k !== 'sign') {
                $sign .= $val;
            }
        }
        return $sign;
    }

    public static function getConfig(bool $refresh = false): array
    {
        if (!self::$config || $refresh) self::$config = array_column(FastappPay::query()->where(['code' => self::KEY])->value('config'), 'text', 'field');
        return self::$config;
    }
}